package net.jeeshop.core.task;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.JobDetailImpl;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;


@Service("taskService")
public class TaskServiceImpl implements TaskService, ApplicationContextAware {

	@Autowired
	SchedulerFactoryBean schedulerFactoryBean;
	
	// 任务列表
	Map<String, TaskBean> taskList = new LinkedHashMap<String, TaskBean>();
	// 应用容器
	private ApplicationContext appcontext;

	@Override
	public Map<String, String> getAllCron() {
		Map<String, String> maps = new HashMap<String, String>();
		for (TaskBean task : taskList.values()) {
			maps.put(task.getId(), task.getCron());
		}
		return maps;
	}

	@Override
	public List<TaskBean> getAllTask() {
		List<TaskBean> list = new ArrayList<TaskBean>();
		for (TaskBean task : taskList.values()) {
			list.add(task);
		}
		return list;
	}

	@Override
	public TaskBean getTaskById(String taskId) {
		return taskList.get(taskId);
	}

	private TaskBean createScheduleTask(Method m) throws Exception {
		TaskBean task = new TaskBean("task-" + System.currentTimeMillis());
		Class<?> clazz = m.getDeclaringClass();
		task.setGroup(clazz.getName());
		task.setTrigger(clazz.getName() + "." + m.getName());
		if (m.isAnnotationPresent(Scheduled.class)) {
			Annotation sc = m.getAnnotation(Scheduled.class);
			Method cm = sc.getClass().getMethod("cron");
			String cron = cm.invoke(sc).toString();
			task.setCron(cron);
		}
		return task;
	}

	/**
	 * 判断spring容器是否包含该类
	 * 
	 * @param c
	 * @return
	 */
	public boolean ctxContainsBean(Class<?> c) {
		try {
			Object obj = appcontext.getBean(c);
			if (obj != null) {
				return true;
			}
		} catch (NoSuchBeanDefinitionException e) {
			return false;
		}
		return false;
	}

	/**
	 * 判断spring容器是否包含该bean
	 * 
	 * @param name
	 * @return
	 */
	public boolean ctxContainsBean(String name) {
		try {
			Object obj = appcontext.getBean(name);
			if (obj != null) {
				return true;
			}
		} catch (NoSuchBeanDefinitionException e) {
			return false;
		}
		return false;
	}

	@Override
	public TaskBean addTask(TaskBean task) throws Exception {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		JobDetailImpl jobDetail = new JobDetailImpl();
		jobDetail.setName(task.getId());
		jobDetail.setGroup(task.getGroup());
		jobDetail.setJobClass(ProxyJob.class);

		TriggerBuilder<Trigger> tig = TriggerBuilder.newTrigger();
		TriggerBuilder<Trigger> tb = tig.withIdentity(task.getTrigger(), task.getTriggerGrop())
				.withIdentity(task.getName(), task.getTriggerGrop());

		TriggerBuilder<CronTrigger> tsb = tb.withSchedule(CronScheduleBuilder.cronSchedule(task.getCron()));

		CronTrigger trigger = (CronTrigger) tsb.build();

		Class<?> clazz = Class.forName(task.getGroup());
		// 无缝集成spring
		Object target = null;

		if (!ctxContainsBean(clazz)) {
			target = clazz.newInstance();
		} else {
			target = appcontext.getBean(clazz);
		}

		Method m = clazz.getMethod(task.getTrigger().replace(task.getGroup() + ".", ""));
		trigger.getJobDataMap().put(ProxyJob.DATA_TARGET_KEY, target);
		trigger.getJobDataMap().put(ProxyJob.DATA_TRIGGER_KEY, m);
		trigger.getJobDataMap().put(ProxyJob.DATA_TRIGGER_PARAM_KEY, new Object[] {});
		trigger.getJobDataMap().put(ProxyJob.DATA_TASK_KEY, task);

		scheduler.scheduleJob(jobDetail, trigger);

		if (!scheduler.isShutdown()) {
			scheduler.start();
		}

		if (!taskList.containsKey(task.getId())) {
			taskList.put(task.getId(), task);
		}

		return task;
	}

	@Override
	public TaskBean addTask(String taskName, String taskClassName, String triggername, String cron)
			throws Exception {
		Class<?> clazz = Class.forName(taskClassName);
		Method m = clazz.getMethod(triggername);
		TaskBean task = createScheduleTask(m);
		task.setName(taskName);
		task.setCron(cron);
		task.setGroup(taskClassName);
		task.setTriggerGrop(taskClassName);
		return addTask(task);
	}

	@Override
	public TaskBean modifyTaskCron(String taskId, String cron) {
		// 获取任务
		TaskBean task = taskList.get(taskId);
		// 停止调
		this.pauseTask(taskId);
		// 修改cron
		task.setCron(cron);
		// 启动
		restartTask(taskId);
		return task;
	}

	@Override
	public TaskBean removeTask(String taskId) {
		TaskBean task = taskList.get(taskId);
		try {
			Scheduler scheduler = schedulerFactoryBean.getScheduler();
			TriggerKey triggerKey = new TriggerKey(taskId, task.getTrigger());
			scheduler.pauseTrigger(triggerKey);
			scheduler.unscheduleJob(triggerKey);
			JobKey jobKey = new JobKey(taskId, task.getGroup());
			scheduler.deleteJob(jobKey);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return task;
	}

	@Override
	public TaskBean restartTask(String taskId) {
		TaskBean task = pauseTask(taskId);
		try {
			Scheduler scheduler = schedulerFactoryBean.getScheduler();
			if (task != null) {
				TriggerKey triggerKey = new TriggerKey(taskId, task.getTrigger());
				scheduler.resumeTrigger(triggerKey);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return task;
	}

	@Override
	public TaskBean pauseTask(String taskId) {
		TaskBean task = taskList.get(taskId);
		try {
			Scheduler scheduler = schedulerFactoryBean.getScheduler();
			TriggerKey triggerKey = new TriggerKey(taskId, task.getTrigger());
			JobKey jobKey = new JobKey(taskId, task.getGroup());
			scheduler.pauseJob(jobKey);
			scheduler.pauseTrigger(triggerKey);
			scheduler.unscheduleJob(triggerKey);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return task;
	}

	@Override
	public TaskBean disableTask(String taskId) {
		TaskBean task = taskList.get(taskId);
		try {
			pauseTask(taskId);
			taskList.remove(taskId);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return task;
	}

	@Override
	public TaskBean shutdownTask(String taskId) {
		// ScheduleTask task = taskList.get(taskId);
		throw new RuntimeException("TaskService.disableTask(String taskId)还没有实现的");
	}

	/**
	 * 创建JobDetail
	 * 
	 * @return
	 */
	private JobDetail createJobDetail(TaskBean task) {
		JobDetailImpl jobDetail = new JobDetailImpl();
		jobDetail.setName(task.getId());
		jobDetail.setGroup(task.getGroup());
		jobDetail.setJobClass(ProxyJob.class);
		return jobDetail;
	}

	/**
	 * 创建CronTrigger
	 * 
	 * @param task
	 * @return
	 */
	private CronTrigger createCronTrigger(TaskBean task) {
		TriggerBuilder<Trigger> tig = TriggerBuilder.newTrigger();
		TriggerBuilder<Trigger> tb = tig.withIdentity(task.getTrigger(), task.getTriggerGrop())
				.withIdentity(task.getName(), task.getTriggerGrop());
		TriggerBuilder<CronTrigger> tsb = tb.withSchedule(CronScheduleBuilder.cronSchedule(task.getCron()));
		CronTrigger trigger = (CronTrigger) tsb.build();
		return trigger;
	}

	@Override
	public void startAllTask() {
		try {
			Scheduler scheduler = schedulerFactoryBean.getScheduler();
			for (TaskBean task : taskList.values()) {
				JobKey jobKey = new JobKey(task.getId(), task.getGroup());
				TriggerKey triggerKey = new TriggerKey(task.getId(), task.getGroup());
				if (!scheduler.checkExists(jobKey) && scheduler.checkExists(triggerKey)) {
					JobDetail jobDetail = createJobDetail(task);
					CronTrigger trigger = createCronTrigger(task);
					scheduler.scheduleJob(jobDetail, trigger);
				}
			}
			if (scheduler.isShutdown()) {
				scheduler.start();
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

	}

	@Override
	public void shutdownAllTask() {
		try {
			Scheduler scheduler = schedulerFactoryBean.getScheduler();
			if (scheduler.isStarted()) {
				scheduler.shutdown(true);
			}
			taskList.clear();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public void setApplicationContext(ApplicationContext appcontext) throws BeansException {
		this.appcontext = appcontext;
		try {
			for (String name : appcontext.getBeanDefinitionNames()) {
				if (!ctxContainsBean(name)) {
					continue;
				}
				Class<?> c = appcontext.getBean(name).getClass();
				for (Method m : c.getMethods()) {
					if (m.isAnnotationPresent(Scheduled.class)) {
						TaskBean task = createScheduleTask(m);
						addTask(task);
					}
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

}
